package com.tbynet.jwp.service.support;

import com.jfinal.log.Log;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 缓存监控器
 * 提供详细的监控指标和健康检查
 */
public class TermCacheMonitor {
    private static final Log log = Log.getLog(TermCacheMonitor.class);

    private final Map<String, AtomicLong> hitCounts = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> missCounts = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> evictionCounts = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> errorCounts = new ConcurrentHashMap<>();
    private final AtomicLong totalOperations = new AtomicLong(0);

    private final TermCacheManager cacheManager;
    private final Date startTime;

    // 性能统计
    private final Map<String, AtomicLong> operationDurations = new ConcurrentHashMap<>();
    private final Map<String, Long> lastOperationTime = new ConcurrentHashMap<>();

    public TermCacheMonitor(TermCacheManager cacheManager) {
        this.cacheManager = cacheManager;
        this.startTime = new Date();
        initializeCounters();
    }

    private void initializeCounters() {
        String[] cacheTypes = {"term", "hierarchy", "taxonomy", "statistics"};
        String[] operations = {"get", "set", "remove", "refresh"};

        for (String type : cacheTypes) {
            hitCounts.put(type, new AtomicLong(0));
            missCounts.put(type, new AtomicLong(0));
            evictionCounts.put(type, new AtomicLong(0));
            errorCounts.put(type, new AtomicLong(0));
        }

        for (String operation : operations) {
            operationDurations.put(operation, new AtomicLong(0));
            lastOperationTime.put(operation, System.currentTimeMillis());
        }
    }

    /**
     * 记录缓存命中
     */
    public void recordHit(String cacheType) {
        AtomicLong counter = hitCounts.get(cacheType);
        if (counter != null) {
            counter.incrementAndGet();
        }
        totalOperations.incrementAndGet();
    }

    /**
     * 记录缓存未命中
     */
    public void recordMiss(String cacheType) {
        AtomicLong counter = missCounts.get(cacheType);
        if (counter != null) {
            counter.incrementAndGet();
        }
        totalOperations.incrementAndGet();
    }

    /**
     * 记录缓存清理
     */
    public void recordEviction(String cacheType) {
        AtomicLong counter = evictionCounts.get(cacheType);
        if (counter != null) {
            counter.incrementAndGet();
        }
    }

    /**
     * 记录缓存错误
     */
    public void recordError(String cacheType) {
        AtomicLong counter = errorCounts.get(cacheType);
        if (counter != null) {
            counter.incrementAndGet();
        }
    }

    /**
     * 记录操作耗时
     */
    public void recordOperationDuration(String operation, long durationMs) {
        AtomicLong counter = operationDurations.get(operation);
        if (counter != null) {
            counter.addAndGet(durationMs);
        }
        lastOperationTime.put(operation, System.currentTimeMillis());
    }

    /**
     * 获取详细的缓存统计信息
     */
    public Map<String, Object> getDetailedCacheStatistics() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("timestamp", new Date());
        stats.put("startTime", startTime);
        stats.put("uptimeMinutes", getUptimeMinutes());
        stats.put("totalOperations", totalOperations.get());

        // 命中率统计
        Map<String, Object> hitRates = new HashMap<>();
        Map<String, Object> operationStats = new HashMap<>();

        for (String cacheType : hitCounts.keySet()) {
            long hits = hitCounts.get(cacheType).get();
            long misses = missCounts.get(cacheType).get();
            long errors = errorCounts.get(cacheType).get();
            long total = hits + misses;

            double hitRate = total > 0 ? (double) hits / total * 100 : 0;
            double errorRate = total > 0 ? (double) errors / total * 100 : 0;

            Map<String, Object> typeStats = new HashMap<>();
            typeStats.put("hitRate", String.format("%.2f%%", hitRate));
            typeStats.put("hits", hits);
            typeStats.put("misses", misses);
            typeStats.put("errors", errors);
            typeStats.put("errorRate", String.format("%.2f%%", errorRate));
            typeStats.put("evictions", evictionCounts.get(cacheType).get());

            hitRates.put(cacheType, typeStats);
        }

        // 操作性能统计
        for (String operation : operationDurations.keySet()) {
            long totalDuration = operationDurations.get(operation).get();
            long count = getOperationCount(operation);
            long avgDuration = count > 0 ? totalDuration / count : 0;

            Map<String, Object> opStats = new HashMap<>();
            opStats.put("totalDurationMs", totalDuration);
            opStats.put("averageDurationMs", avgDuration);
            opStats.put("lastOperationTime", new Date(lastOperationTime.get(operation)));

            operationStats.put(operation, opStats);
        }

        stats.put("cacheTypeStats", hitRates);
        stats.put("operationStats", operationStats);
        stats.put("healthStatus", checkHealthStatus());

        // 系统级统计
        stats.put("systemStats", cacheManager.getCacheStats());

        return stats;
    }

    /**
     * 检查缓存健康状况
     */
    public Map<String, Object> checkHealthStatus() {
        Map<String, Object> health = new HashMap<>();
        health.put("timestamp", new Date());

        boolean isHealthy = true;
        List<String> issues = new ArrayList<>();

        // 检查错误率
        for (String cacheType : errorCounts.keySet()) {
            long errors = errorCounts.get(cacheType).get();
            long total = hitCounts.get(cacheType).get() + missCounts.get(cacheType).get();

            if (total > 100 && errors > total * 0.1) { // 错误率超过10%
                issues.add(String.format("%s缓存错误率过高: %.1f%%", cacheType, (double)errors/total*100));
                isHealthy = false;
            }
        }

        // 检查命中率（如果太低可能有问题）
        for (String cacheType : hitCounts.keySet()) {
            long hits = hitCounts.get(cacheType).get();
            long total = hits + missCounts.get(cacheType).get();

            if (total > 1000 && (double)hits/total < 0.3) { // 命中率低于30%
                issues.add(String.format("%s缓存命中率过低: %.1f%%", cacheType, (double)hits/total*100));
            }
        }

        health.put("status", isHealthy ? "HEALTHY" : "DEGRADED");
        health.put("issues", issues);
        health.put("recommendations", generateRecommendations(issues));

        return health;
    }

    /**
     * 生成优化建议
     */
    private List<String> generateRecommendations(List<String> issues) {
        List<String> recommendations = new ArrayList<>();

        if (issues.stream().anyMatch(issue -> issue.contains("错误率过高"))) {
            recommendations.add("检查缓存服务器连接和配置");
            recommendations.add("考虑增加缓存降级策略");
        }

        if (issues.stream().anyMatch(issue -> issue.contains("命中率过低"))) {
            recommendations.add("优化缓存键设计");
            recommendations.add("调整缓存过期策略");
            recommendations.add("考虑增加缓存预热");
        }

        if (recommendations.isEmpty()) {
            recommendations.add("缓存系统运行良好，继续保持");
        }

        return recommendations;
    }

    private long getUptimeMinutes() {
        return (System.currentTimeMillis() - startTime.getTime()) / (1000 * 60);
    }

    private long getOperationCount(String operation) {
        // 根据操作类型估算操作次数
        switch (operation) {
            case "get":
                return hitCounts.values().stream().mapToLong(AtomicLong::get).sum() +
                        missCounts.values().stream().mapToLong(AtomicLong::get).sum();
            case "set":
                return totalOperations.get() / 3; // 估算值
            default:
                return totalOperations.get() / 10; // 估算值
        }
    }
}